{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Stellargraph example: Heterogeneous GraphSAGE on the Movielens recommendation dataset"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this example, we use our generalisation of the [GraphSAGE](http://snap.stanford.edu/graphsage/) algorithm to heterogeneous graphs (which we call HinSAGE) to build a model that predicts user-movie ratings in the Movielens dataset (see below). The problem is treated as a supervised link attribute inference problem on a user-movie network with nodes of two types (users and movies, both attributed) and links corresponding to user-movie ratings, with integer `rating` attributes from 1 to 5 (note that if a user hasn't rated a movie, the corresponding user-movie link does not exist in the network).\n",
    "\n",
    "To address this problem, we build a model with the following architecture: a two-layer HinSAGE model that takes labeled `(user, movie)` node pairs corresponding to user-movie ratings, and outputs a pair of node embeddings for the `user` and `movie` nodes of the pair. These embeddings are then fed into a link regression layer, which applies a binary operator to those node embeddings (e.g., concatenating them) to construct the link embedding. Thus obtained link embeddings are passed through the link regression layer to obtain predicted user-movie ratings. The entire model is trained end-to-end by minimizing the loss function of choice (e.g., root mean square error between predicted and true ratings) using stochastic gradient descent (SGD) updates of the model parameters, with minibatches of user-movie training links fed into the model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "from sklearn import preprocessing, feature_extraction, model_selection\n",
    "from sklearn.metrics import mean_absolute_error, mean_squared_error\n",
    "\n",
    "import stellargraph as sg\n",
    "from stellargraph.mapper import HinSAGELinkGenerator\n",
    "from stellargraph.layer import HinSAGE, link_regression\n",
    "from tensorflow.keras import Model, optimizers, losses, metrics\n",
    "\n",
    "import multiprocessing\n",
    "import utils\n",
    "from stellargraph import datasets\n",
    "from IPython.display import display, HTML"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Load the dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "The MovieLens 100K dataset contains 100,000 ratings from 943 users on 1682 movies."
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "MovieLens dataset is already downloaded\n"
     ]
    }
   ],
   "source": [
    "dataset = datasets.MovieLens()\n",
    "display(HTML(dataset.description))\n",
    "dataset.download()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "with open(\"ml-100k-config.json\", \"r\") as f:\n",
    "    config = json.load(f)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ingest the ratings into a user-movie graph:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Graph statistics: 943 users, 1682 movies, 100000 ratings\n"
     ]
    }
   ],
   "source": [
    "Gnx, id_map, inv_id_map = utils.ingest_graph(dataset.data_directory, config)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ingest user and movie features:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "user_features = utils.ingest_features(dataset.data_directory, config, node_type=\"users\")\n",
    "movie_features = utils.ingest_features(dataset.data_directory, config, node_type=\"movies\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Explore user and movie features:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>age</th>\n",
       "      <th>gender</th>\n",
       "      <th>job</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>uId</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>24</td>\n",
       "      <td>M</td>\n",
       "      <td>technician</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>53</td>\n",
       "      <td>F</td>\n",
       "      <td>other</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>23</td>\n",
       "      <td>M</td>\n",
       "      <td>writer</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>24</td>\n",
       "      <td>M</td>\n",
       "      <td>technician</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>33</td>\n",
       "      <td>F</td>\n",
       "      <td>other</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "     age gender         job\n",
       "uId                        \n",
       "1     24      M  technician\n",
       "2     53      F       other\n",
       "3     23      M      writer\n",
       "4     24      M  technician\n",
       "5     33      F       other"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "user_features.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>g1</th>\n",
       "      <th>g2</th>\n",
       "      <th>g3</th>\n",
       "      <th>g4</th>\n",
       "      <th>g5</th>\n",
       "      <th>g6</th>\n",
       "      <th>g7</th>\n",
       "      <th>g8</th>\n",
       "      <th>g9</th>\n",
       "      <th>g10</th>\n",
       "      <th>g11</th>\n",
       "      <th>g12</th>\n",
       "      <th>g13</th>\n",
       "      <th>g14</th>\n",
       "      <th>g15</th>\n",
       "      <th>g16</th>\n",
       "      <th>g17</th>\n",
       "      <th>g18</th>\n",
       "      <th>g19</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>mId</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "     g1  g2  g3  g4  g5  g6  g7  g8  g9  g10  g11  g12  g13  g14  g15  g16  \\\n",
       "mId                                                                          \n",
       "1     0   0   0   1   1   1   0   0   0    0    0    0    0    0    0    0   \n",
       "2     0   1   1   0   0   0   0   0   0    0    0    0    0    0    0    0   \n",
       "3     0   0   0   0   0   0   0   0   0    0    0    0    0    0    0    0   \n",
       "4     0   1   0   0   0   1   0   0   1    0    0    0    0    0    0    0   \n",
       "5     0   0   0   0   0   0   1   0   1    0    0    0    0    0    0    0   \n",
       "\n",
       "     g17  g18  g19  \n",
       "mId                 \n",
       "1      0    0    0  \n",
       "2      1    0    0  \n",
       "3      1    0    0  \n",
       "4      0    0    0  \n",
       "5      1    0    0  "
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "movie_features.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Prepare the user features for machine learning (ML) by transforming them to numeric feature vectors required by the HinSAGE model (movie features are already numeric and hence ML-ready):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Names of user features than require transforming to numeric features:\n",
    "feature_names = [\"age\", \"gender\", \"job\"]\n",
    "\n",
    "feature_encoding = feature_extraction.DictVectorizer(sparse=False, dtype=float)\n",
    "user_features_transformed = feature_encoding.fit_transform(\n",
    "    user_features[feature_names].to_dict(\"records\")\n",
    ")\n",
    "\n",
    "# Assume that the age can be used as a continuous variable and rescale it\n",
    "user_features_transformed[:, 0] = preprocessing.scale(user_features_transformed[:, 0])\n",
    "\n",
    "# Put features back in DataFrame\n",
    "user_features = pd.DataFrame(\n",
    "    user_features_transformed, index=user_features.index, dtype=\"float64\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Add the user and movie features to the graph:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "Gnx = utils.add_features_to_nodes(Gnx, inv_id_map, user_features, movie_features)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Split Gnx.edges() into train and test sets for model training/evaluation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "edges = list(Gnx.edges(data=True))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Use 70% of edges for training, the rest for testing:\n",
    "edges_train, edges_test = model_selection.train_test_split(\n",
    "    edges, train_size=0.7, test_size=0.3\n",
    ")\n",
    "\n",
    "edgelist_train = [(e[0], e[1]) for e in edges_train]\n",
    "edgelist_test = [(e[0], e[1]) for e in edges_test]\n",
    "\n",
    "labels_train = [e[2][\"score\"] for e in edges_train]\n",
    "labels_test = [e[2][\"score\"] for e in edges_test]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Our machine learning task of learning user-movie ratings can be framed as a supervised Link Attribute Inference: given a graph of user-movie ratings, we train a model for rating prediction using the ratings edges_train, and evaluate it using the test ratings edges_test. The model also requires the user-movie graph structure, to do the neighbour sampling required by the HinSAGE algorithm.\n",
    "\n",
    "To proceed, we need to create a StellarGraph object from the ingested graph, for training the model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# When sampling the GraphSAGE subgraphs, we want to treat user-movie links as undirected\n",
    "G = sg.StellarGraph(Gnx, node_features=\"feature\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we are ready for our ML task of learning to predict user-movie ratings!\n",
    "\n",
    "Summary of the prepared ML-ready StellarGraph:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "StellarGraph: Undirected multigraph\n",
      " Nodes: 2625, Edges: 100000\n",
      "\n",
      " Node types:\n",
      "  movie: [1682]\n",
      "        Attributes: {'feature'}\n",
      "    Edge types: movie-default->user\n",
      "  user: [943]\n",
      "        Attributes: {'feature'}\n",
      "    Edge types: user-default->movie\n",
      "\n",
      " Edge types:\n",
      "    movie-default->user: [74198]\n",
      "        Attributes: {'uId', 'score', 'mId'}\n",
      "    user-default->movie: [25802]\n",
      "        Attributes: {'uId', 'score', 'mId'}\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(G.info())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we create the link mappers for sampling and streaming training and testing data to the model. The link mappers essentially \"map\" user-movie links to the input of HinSAGE: they take minibatches of user-movie links, sample 2-hop subgraphs of G with `(user, movie)` head nodes extracted from those user-movie links, and feed them, together with the corresponding user-movie ratings, to the input layer of the HinSAGE model, for SGD updates of the model parameters.\n",
    "\n",
    "Specify the minibatch size (number of user-movie links per minibatch) and the number of epochs for training the ML model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "batch_size = 200\n",
    "epochs = 20"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Specify the sizes of 1- and 2-hop neighbour samples for HinSAGE:\n",
    "\n",
    "Note that the length of `num_samples` list defines the number of layers/iterations in the HinSAGE model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "num_samples = [8, 4]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Create the generators to feed data from the graph to the Keras model. We need to specify the nodes types for the user-movie pairs that we will feed to the model. The `shuffle=True` argument is given to the `flow` method to improve training."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "generator = HinSAGELinkGenerator(\n",
    "    G, batch_size, num_samples, head_node_types=[\"user\", \"movie\"]\n",
    ")\n",
    "train_gen = generator.flow(edgelist_train, labels_train, shuffle=True)\n",
    "test_gen = generator.flow(edgelist_test, labels_test)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Build the model by stacking a two-layer HinSAGE model and a link regression layer on top.\n",
    "\n",
    "First, we define the HinSAGE part of the model, with hidden layer sizes of 32 for both HinSAGE layers, a bias term, and no dropout. (Dropout can be switched on by specifying a positive `dropout` rate, `0 < dropout < 1`)\n",
    "\n",
    "Note that the length of `layer_sizes` list must be equal to the length of `num_samples`, as `len(num_samples)` defines the number of hops (layers) in the HinSAGE model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "hinsage_layer_sizes = [32, 32]\n",
    "assert len(hinsage_layer_sizes) == len(num_samples)\n",
    "\n",
    "hinsage = HinSAGE(\n",
    "    layer_sizes=hinsage_layer_sizes, generator=generator, bias=True, dropout=0.0\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Expose input and output sockets of hinsage:\n",
    "x_inp, x_out = hinsage.build()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Add the final estimator layer for predicting the ratings. The edge_embedding_method argument specifies the way in which node representations (node embeddings) are combined into link representations (recall that links represent user-movie ratings, and are thus pairs of (user, movie) nodes). In this example, we will use 'concat', i.e., node embeddings are concatenated to get link embeddings."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "link_regression: using 'concat' method to combine node embeddings into edge embeddings\n"
     ]
    }
   ],
   "source": [
    "# Final estimator layer\n",
    "score_prediction = link_regression(edge_embedding_method=\"concat\")(x_out)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Create the Keras model, and compile it by specifying the optimizer, loss function to optimise, and metrics for diagnostics:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow.keras.backend as K\n",
    "\n",
    "\n",
    "def root_mean_square_error(s_true, s_pred):\n",
    "    return K.sqrt(K.mean(K.pow(s_true - s_pred, 2)))\n",
    "\n",
    "\n",
    "model = Model(inputs=x_inp, outputs=score_prediction)\n",
    "model.compile(\n",
    "    optimizer=optimizers.Adam(lr=1e-2),\n",
    "    loss=losses.mean_squared_error,\n",
    "    metrics=[root_mean_square_error, metrics.mae],\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Summary of the model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"model\"\n",
      "__________________________________________________________________________________________________\n",
      "Layer (type)                    Output Shape         Param #     Connected to                     \n",
      "==================================================================================================\n",
      "input_3 (InputLayer)            [(None, 8, 19)]      0                                            \n",
      "__________________________________________________________________________________________________\n",
      "input_5 (InputLayer)            [(None, 32, 24)]     0                                            \n",
      "__________________________________________________________________________________________________\n",
      "input_6 (InputLayer)            [(None, 32, 19)]     0                                            \n",
      "__________________________________________________________________________________________________\n",
      "input_1 (InputLayer)            [(None, 1, 24)]      0                                            \n",
      "__________________________________________________________________________________________________\n",
      "reshape (Reshape)               (None, 1, 8, 19)     0           input_3[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "reshape_2 (Reshape)             (None, 8, 4, 24)     0           input_5[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "input_4 (InputLayer)            [(None, 8, 24)]      0                                            \n",
      "__________________________________________________________________________________________________\n",
      "reshape_3 (Reshape)             (None, 8, 4, 19)     0           input_6[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "dropout_1 (Dropout)             (None, 1, 24)        0           input_1[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "dropout (Dropout)               (None, 1, 8, 19)     0           reshape[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "dropout_5 (Dropout)             (None, 8, 19)        0           input_3[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "dropout_4 (Dropout)             (None, 8, 4, 24)     0           reshape_2[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "input_2 (InputLayer)            [(None, 1, 19)]      0                                            \n",
      "__________________________________________________________________________________________________\n",
      "reshape_1 (Reshape)             (None, 1, 8, 24)     0           input_4[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "dropout_7 (Dropout)             (None, 8, 24)        0           input_4[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "dropout_6 (Dropout)             (None, 8, 4, 19)     0           reshape_3[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "mean_hin_aggregator (MeanHinAgg multiple             720         dropout_1[0][0]                  \n",
      "                                                                 dropout[0][0]                    \n",
      "                                                                 dropout_7[0][0]                  \n",
      "                                                                 dropout_6[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "mean_hin_aggregator_1 (MeanHinA multiple             720         dropout_3[0][0]                  \n",
      "                                                                 dropout_2[0][0]                  \n",
      "                                                                 dropout_5[0][0]                  \n",
      "                                                                 dropout_4[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "dropout_3 (Dropout)             (None, 1, 19)        0           input_2[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "dropout_2 (Dropout)             (None, 1, 8, 24)     0           reshape_1[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "reshape_4 (Reshape)             (None, 1, 8, 32)     0           mean_hin_aggregator_1[1][0]      \n",
      "__________________________________________________________________________________________________\n",
      "reshape_5 (Reshape)             (None, 1, 8, 32)     0           mean_hin_aggregator[1][0]        \n",
      "__________________________________________________________________________________________________\n",
      "dropout_9 (Dropout)             (None, 1, 32)        0           mean_hin_aggregator[0][0]        \n",
      "__________________________________________________________________________________________________\n",
      "dropout_8 (Dropout)             (None, 1, 8, 32)     0           reshape_4[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "dropout_11 (Dropout)            (None, 1, 32)        0           mean_hin_aggregator_1[0][0]      \n",
      "__________________________________________________________________________________________________\n",
      "dropout_10 (Dropout)            (None, 1, 8, 32)     0           reshape_5[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "mean_hin_aggregator_2 (MeanHinA (None, 1, 32)        1056        dropout_9[0][0]                  \n",
      "                                                                 dropout_8[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "mean_hin_aggregator_3 (MeanHinA (None, 1, 32)        1056        dropout_11[0][0]                 \n",
      "                                                                 dropout_10[0][0]                 \n",
      "__________________________________________________________________________________________________\n",
      "reshape_6 (Reshape)             (None, 32)           0           mean_hin_aggregator_2[0][0]      \n",
      "__________________________________________________________________________________________________\n",
      "reshape_7 (Reshape)             (None, 32)           0           mean_hin_aggregator_3[0][0]      \n",
      "__________________________________________________________________________________________________\n",
      "lambda (Lambda)                 (None, 32)           0           reshape_6[0][0]                  \n",
      "                                                                 reshape_7[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "concatenate (Concatenate)       (None, 64)           0           lambda[0][0]                     \n",
      "                                                                 lambda[1][0]                     \n",
      "__________________________________________________________________________________________________\n",
      "dense (Dense)                   (None, 1)            65          concatenate[0][0]                \n",
      "__________________________________________________________________________________________________\n",
      "reshape_8 (Reshape)             (None, 1)            0           dense[0][0]                      \n",
      "==================================================================================================\n",
      "Total params: 3,617\n",
      "Trainable params: 3,617\n",
      "Non-trainable params: 0\n",
      "__________________________________________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Specify the number of workers to use for model training (relevant only when multiprocessing=True)\n",
    "num_workers = multiprocessing.cpu_count() // 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Evaluate the fresh (untrained) model on the test set (for reference):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "150/150 [==============================] - 4s 29ms/step - loss: 12.6772 - root_mean_square_error: 3.5598 - mean_absolute_error: 3.3761\n",
      "Untrained model's Test Evaluation:\n",
      "\tloss: 12.6772\n",
      "\troot_mean_square_error: 3.5598\n",
      "\tmean_absolute_error: 3.3761\n"
     ]
    }
   ],
   "source": [
    "test_metrics = model.evaluate_generator(\n",
    "    test_gen, verbose=1, use_multiprocessing=True, workers=num_workers\n",
    ")\n",
    "\n",
    "print(\"Untrained model's Test Evaluation:\")\n",
    "for name, val in zip(model.metrics_names, test_metrics):\n",
    "    print(\"\\t{}: {:0.4f}\".format(name, val))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Train the model by feeding the data from the graph in minibatches, using mapper_train, and get validation metrics after each epoch:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/20\n",
      "350/350 [==============================] - 18s 50ms/step - loss: 1.3410 - root_mean_square_error: 1.1340 - mean_absolute_error: 0.9376 - val_loss: 1.1506 - val_root_mean_square_error: 1.0716 - val_mean_absolute_error: 0.8731\n",
      "Epoch 2/20\n",
      "350/350 [==============================] - 15s 42ms/step - loss: 1.1569 - root_mean_square_error: 1.0745 - mean_absolute_error: 0.8727 - val_loss: 1.1477 - val_root_mean_square_error: 1.0704 - val_mean_absolute_error: 0.8800\n",
      "Epoch 3/20\n",
      "350/350 [==============================] - 15s 42ms/step - loss: 1.1384 - root_mean_square_error: 1.0659 - mean_absolute_error: 0.8640 - val_loss: 1.1308 - val_root_mean_square_error: 1.0624 - val_mean_absolute_error: 0.8653\n",
      "Epoch 4/20\n",
      "350/350 [==============================] - 15s 43ms/step - loss: 1.1275 - root_mean_square_error: 1.0608 - mean_absolute_error: 0.8586 - val_loss: 1.1109 - val_root_mean_square_error: 1.0529 - val_mean_absolute_error: 0.8479\n",
      "Epoch 5/20\n",
      "350/350 [==============================] - 16s 45ms/step - loss: 1.1204 - root_mean_square_error: 1.0573 - mean_absolute_error: 0.8544 - val_loss: 1.1048 - val_root_mean_square_error: 1.0500 - val_mean_absolute_error: 0.8462\n",
      "Epoch 6/20\n",
      "350/350 [==============================] - 16s 47ms/step - loss: 1.1132 - root_mean_square_error: 1.0539 - mean_absolute_error: 0.8524 - val_loss: 1.1113 - val_root_mean_square_error: 1.0530 - val_mean_absolute_error: 0.8421\n",
      "Epoch 7/20\n",
      "350/350 [==============================] - 19s 54ms/step - loss: 1.1071 - root_mean_square_error: 1.0509 - mean_absolute_error: 0.8495 - val_loss: 1.1137 - val_root_mean_square_error: 1.0542 - val_mean_absolute_error: 0.8433\n",
      "Epoch 8/20\n",
      "350/350 [==============================] - 19s 54ms/step - loss: 1.1028 - root_mean_square_error: 1.0490 - mean_absolute_error: 0.8472 - val_loss: 1.1103 - val_root_mean_square_error: 1.0525 - val_mean_absolute_error: 0.8400\n",
      "Epoch 9/20\n",
      "350/350 [==============================] - 16s 46ms/step - loss: 1.1002 - root_mean_square_error: 1.0477 - mean_absolute_error: 0.8467 - val_loss: 1.0996 - val_root_mean_square_error: 1.0475 - val_mean_absolute_error: 0.8421\n",
      "Epoch 10/20\n",
      "350/350 [==============================] - 17s 47ms/step - loss: 1.0971 - root_mean_square_error: 1.0462 - mean_absolute_error: 0.8457 - val_loss: 1.0926 - val_root_mean_square_error: 1.0441 - val_mean_absolute_error: 0.8412\n",
      "Epoch 11/20\n",
      "350/350 [==============================] - 16s 46ms/step - loss: 1.0938 - root_mean_square_error: 1.0446 - mean_absolute_error: 0.8439 - val_loss: 1.1073 - val_root_mean_square_error: 1.0510 - val_mean_absolute_error: 0.8348\n",
      "Epoch 12/20\n",
      "350/350 [==============================] - 16s 46ms/step - loss: 1.0931 - root_mean_square_error: 1.0444 - mean_absolute_error: 0.8432 - val_loss: 1.0908 - val_root_mean_square_error: 1.0434 - val_mean_absolute_error: 0.8495\n",
      "Epoch 13/20\n",
      "350/350 [==============================] - 16s 47ms/step - loss: 1.0899 - root_mean_square_error: 1.0429 - mean_absolute_error: 0.8416 - val_loss: 1.0996 - val_root_mean_square_error: 1.0477 - val_mean_absolute_error: 0.8526\n",
      "Epoch 14/20\n",
      "350/350 [==============================] - 16s 46ms/step - loss: 1.0900 - root_mean_square_error: 1.0429 - mean_absolute_error: 0.8428 - val_loss: 1.0923 - val_root_mean_square_error: 1.0440 - val_mean_absolute_error: 0.8330\n",
      "Epoch 15/20\n",
      "350/350 [==============================] - 17s 47ms/step - loss: 1.0858 - root_mean_square_error: 1.0408 - mean_absolute_error: 0.8394 - val_loss: 1.1010 - val_root_mean_square_error: 1.0482 - val_mean_absolute_error: 0.8493\n",
      "Epoch 16/20\n",
      "350/350 [==============================] - 16s 47ms/step - loss: 1.0870 - root_mean_square_error: 1.0414 - mean_absolute_error: 0.8403 - val_loss: 1.0827 - val_root_mean_square_error: 1.0394 - val_mean_absolute_error: 0.8321\n",
      "Epoch 17/20\n",
      "350/350 [==============================] - 14s 40ms/step - loss: 1.0860 - root_mean_square_error: 1.0408 - mean_absolute_error: 0.8401 - val_loss: 1.0818 - val_root_mean_square_error: 1.0390 - val_mean_absolute_error: 0.8376\n",
      "Epoch 18/20\n",
      "350/350 [==============================] - 19s 54ms/step - loss: 1.0828 - root_mean_square_error: 1.0394 - mean_absolute_error: 0.8382 - val_loss: 1.0794 - val_root_mean_square_error: 1.0379 - val_mean_absolute_error: 0.8354\n",
      "Epoch 19/20\n",
      "350/350 [==============================] - 27s 77ms/step - loss: 1.0814 - root_mean_square_error: 1.0387 - mean_absolute_error: 0.8381 - val_loss: 1.0795 - val_root_mean_square_error: 1.0378 - val_mean_absolute_error: 0.8323\n",
      "Epoch 20/20\n",
      "350/350 [==============================] - 20s 56ms/step - loss: 1.0802 - root_mean_square_error: 1.0380 - mean_absolute_error: 0.8369 - val_loss: 1.0746 - val_root_mean_square_error: 1.0356 - val_mean_absolute_error: 0.8364\n"
     ]
    }
   ],
   "source": [
    "history = model.fit_generator(\n",
    "    train_gen,\n",
    "    validation_data=test_gen,\n",
    "    epochs=epochs,\n",
    "    verbose=1,\n",
    "    shuffle=False,\n",
    "    use_multiprocessing=True,\n",
    "    workers=num_workers,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Plot the training history:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "def plot_history(history):\n",
    "    metrics = sorted(history.history.keys())\n",
    "    metrics = metrics[:len(metrics)//2]\n",
    "    for m in metrics:\n",
    "        # summarize history for metric m\n",
    "        plt.plot(history.history[m])\n",
    "        plt.plot(history.history['val_' + m])\n",
    "        plt.title(m)\n",
    "        plt.ylabel(m)\n",
    "        plt.xlabel('epoch')\n",
    "        plt.legend(['train', 'test'], loc='best')\n",
    "        plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_history(history)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Evaluate the trained model on test user-movie rankings:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "150/150 [==============================] - 4s 26ms/step - loss: 1.0736 - root_mean_square_error: 1.0351 - mean_absolute_error: 0.8360\n",
      "Test Evaluation:\n",
      "\tloss: 1.0736\n",
      "\troot_mean_square_error: 1.0351\n",
      "\tmean_absolute_error: 0.8360\n"
     ]
    }
   ],
   "source": [
    "test_metrics = model.evaluate_generator(\n",
    "    test_gen, use_multiprocessing=True, workers=num_workers, verbose=1\n",
    ")\n",
    "\n",
    "print(\"Test Evaluation:\")\n",
    "for name, val in zip(model.metrics_names, test_metrics):\n",
    "    print(\"\\t{}: {:0.4f}\".format(name, val))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Compare the predicted test rankings with \"mean baseline\" rankings, to see how much better our model does compared to this (very simplistic) baseline:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Mean Baseline Test set metrics:\n",
      "\troot_mean_square_error =  1.1232728292311234\n",
      "\tmean_absolute_error =  0.942265771484375\n",
      "\n",
      "Model Test set metrics:\n",
      "\troot_mean_square_error =  1.0356332064499043\n",
      "\tmean_absolute_error =  0.8357973554541668\n"
     ]
    }
   ],
   "source": [
    "y_true = labels_test\n",
    "# Predict the rankings using the model:\n",
    "y_pred = model.predict_generator(test_gen)\n",
    "# Mean baseline rankings = mean movie ranking:\n",
    "y_pred_baseline = np.full_like(y_pred, np.mean(y_true))\n",
    "\n",
    "rmse = np.sqrt(mean_squared_error(y_true, y_pred_baseline))\n",
    "mae = mean_absolute_error(y_true, y_pred_baseline)\n",
    "print(\"Mean Baseline Test set metrics:\")\n",
    "print(\"\\troot_mean_square_error = \", rmse)\n",
    "print(\"\\tmean_absolute_error = \", mae)\n",
    "\n",
    "rmse = np.sqrt(mean_squared_error(y_true, y_pred))\n",
    "mae = mean_absolute_error(y_true, y_pred)\n",
    "print(\"\\nModel Test set metrics:\")\n",
    "print(\"\\troot_mean_square_error = \", rmse)\n",
    "print(\"\\tmean_absolute_error = \", mae)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Compare the distributions of predicted and true rankings for the test set:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "h_true = plt.hist(y_true, bins=30, facecolor=\"green\", alpha=0.5)\n",
    "h_pred = plt.hist(y_pred, bins=30, facecolor=\"blue\", alpha=0.5)\n",
    "plt.xlabel(\"ranking\")\n",
    "plt.ylabel(\"count\")\n",
    "plt.legend((\"True\", \"Predicted\"))\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We see that our model beats the \"mean baseline\" by a significant margin. To further improve the model, you can try increasing the number of training epochs, change the dropout rate, change the sample sizes for subgraph sampling `num_samples`, hidden layer sizes `layer_sizes` of the HinSAGE part of the model, or try increasing the number of HinSAGE layers.\n",
    "\n",
    "However, note that the distribution of predicted scores is still very narrow, and rarely gives 1, 2 or 5 as a score."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This model uses a bipartite user-movie graph to learn to predict movie ratings. It can be further enhanced by using additional relations, e.g., friendships between users, if they become available. And the best part is: the underlying algorithm of the model does not need to change at all to take these extra relations into account - all that changes is the graph that it learns from!"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
